package agentsSME;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Random;

import otherOrganizations.ServiceCompany;
import main.BuildModel;
import main.Organization;
import enviornment.Clock;
import enviornment.FloodWarning;
import enviornment.Location;

/**
 * Creates a SME agent.

 * @author Chunhui Li
 *
 */

public abstract class SME {
	private String serialNo;
	protected String companyName;
	protected String businessCode;
	protected int numberEmployees;
	protected int employeesAtWork;
	private double turnOver;
	protected Location location;
	protected Premise premises;
	private boolean multiLocation;
	private String sector;
	protected Stock stock;
	protected double regularStock;
	
	protected boolean hasEmergencyPlan;
	private boolean hasFloodExperience;
	protected boolean coveredByInsurance;
	protected boolean receiveWarning;//this is used as a flag when the sme receive a new warning
	protected boolean isSubscriber;
	protected LinkedList<ServiceCompany> serviceContacts;
	
	protected boolean cashAvailableForRecovery;
	protected boolean hasEngineers;
	protected boolean ownership; //true for self-own; false for leased
	protected boolean trafficOn; //?
	protected boolean powerOn; // true for on; false for off
	protected boolean hasElectrician;
	protected boolean hasGoodWorkSpirit;
	protected boolean isFlooded;
	protected boolean trustEA;
	protected double waterInBuilding;
	protected LinkedList<Double> waterHistory;
	protected boolean getServiced;
	
	protected LinkedList<BehaviourSME> availableBehaviours;
	protected BehaviourSME currentBehaviour;
	private ContactsOfSme contacts;
	private LinkedList<SME> neighbours;
	private LinkedList<SME> mutualAid;
	
	protected Clock clock;
	protected Employee[] employees;
	protected int numberVacancy;
	private Random random= new Random();
	
	protected double operationLevel;
	protected boolean perceivedDanger;
	protected boolean improvedPhoneSystem;
	protected boolean raisedEquipment;
	protected boolean raisedStock;
	protected boolean raiseddocuments;
	protected boolean stockSafe;
	protected boolean sandbagsOnsite;
	protected boolean hasBundWall;
	protected boolean backedUpDocuments;
	protected boolean preparedContacts;
	protected boolean instructionsOn;
	protected boolean hasBCPlan;
	protected boolean updatePlan;
	protected boolean protectedBuilding;
	protected boolean adaptedBuilding;
	protected String capability;
	protected boolean participateMutualAid;
//	protected boolean
	protected MsgSender sender;
	protected MsgReceiver receiver;
	//protected double impactFactor;
    /**
     * the constructor of a SME agent.
     */
	public SME(){
		
		serialNo= " ";
		companyName =" ";
		businessCode = " ";				
		numberEmployees = 10;
		employeesAtWork= numberEmployees; // need to update it
		//employees = new Employee[numberEmployees];
		perceivedDanger=false;
		turnOver = random.nextInt(10)+2;
		location = new Location (0,0);
		premises = new Premise(1, location, 2);
		this.setStock(new Stock(60.0,0.5,0.5));// stock units, ration of gound location, ratio of fragile stock		
		regularStock=stock.getStockLevel();
		
		multiLocation = random.nextBoolean();
		sector = " ";
		hasEmergencyPlan = random.nextBoolean();
		hasFloodExperience = false;
		coveredByInsurance = true;
	    receiveWarning = false;
	    ownership = random.nextBoolean();
	    trafficOn = false;
	    powerOn = false;
		trustEA= true;//random.nextBoolean();
		isSubscriber=false;
	    cashAvailableForRecovery = false;//random.nextBoolean();
	    hasEngineers = true;//random.nextBoolean();
	    hasGoodWorkSpirit = false;//random.nextBoolean();
	    hasElectrician =true; //random.nextBoolean();
	    availableBehaviours = new LinkedList<BehaviourSME>();
	   	contacts = new ContactsOfSme (this);
	   	neighbours = new LinkedList<SME>();
	   	mutualAid=new LinkedList<SME>();
	   	isFlooded=false;
	   	waterInBuilding=0.0;
	   	waterHistory=new LinkedList<Double>();
	   	numberVacancy=2;
	   	//behaviour change
	   	hasBundWall= false;//random.nextBoolean();// by default, the bund wall is 1 meters high.
	   	getServiced=false;
	   	
	   	clock = new Clock();
	   	serviceContacts=new LinkedList<ServiceCompany>();
	   	sender= new MsgSender(this);
	   	receiver=new MsgReceiver();
	   	
	   	mutualAid=new LinkedList<SME>();
	   	setCapability(" ");
	   	participateMutualAid=false;
	}
	
	public void setParticipation(boolean b){
		participateMutualAid=b;
	}
	public boolean getParticipation(){
		return participateMutualAid;
	}
	public Stock getStock(){
		return stock;		
	}
	public void setStock(Stock s){
		stock=s;
	}
	public double getRegularStockLevel(){
		return regularStock;
	}
	public void setRegularStockLevel(double d){
		regularStock=d;
	}
	public void makeMutualAidAgreementWith(SME sme){
		mutualAid.add(sme);
	}
	public LinkedList<SME> getMutualAider(){
		return mutualAid;
	}
	public String getCapability(){
		return capability;
	}
	public void setCapability(String c){
		capability=c;
	}
	public void addServiceContact(ServiceCompany sc){
		serviceContacts.add(sc);
	}
	public LinkedList<ServiceCompany> GetServiceCompanyList(){
		return serviceContacts;
	}
	public boolean getServiceStatus(){
		return getServiced;
	}
	public void setServiced(boolean b){
		getServiced=b;
	}
	
	public boolean getTrustEA(){
		return trustEA;
	}
	public void setTrustEA(boolean b){
		
	}
	public boolean getFlooded(){
		return isFlooded;
	}
	public void setFlooded(boolean f){
		isFlooded=f;
	}
	public BehaviourSME getCurrentBehaviour(){
		return currentBehaviour;
	}
	public double getOperationLevel(){
		return operationLevel;
	}
	public void setOperationLevel(double ol){
		operationLevel= ol;
	}
	public double getWaterInBuilding(){
		return waterInBuilding;
	}
	public void setWaterInBuilding(double w){
		waterInBuilding = w;
	}
	public boolean hasFloodExperience(){
		return hasFloodExperience;
	}
	public void setFloodExperience(boolean b){
		hasFloodExperience = b;
	}
	public boolean receivedWarning(){
		return receiveWarning;
	}
	public void setReceiveWarning(boolean b){
		receiveWarning = b;
	}
	public boolean hasEmergencyPlan(){
		return hasEmergencyPlan;
	}
	public void setHasEmergencyPlan(boolean b){
		hasEmergencyPlan = b;
	}
	
	public boolean ownPremise(){
		return ownership;
	}
	public void setOwnership(boolean b){
		ownership = b;
	}
	public boolean getSubscriber(){
		return isSubscriber;
	}
	public void setSubscriber(boolean b){
		isSubscriber=b;
	}
	public Location getLocation(){
		return location;
	}
	public void setLocation (Location loc){
		location = loc;
	}
	public void setPerceived(boolean x){
		perceivedDanger = x;
	}
	public boolean getPerceivedDanger(){
		return perceivedDanger;
	}
	public int getSize(){
		return numberEmployees;
	}
	public void setSize(int x){
		numberEmployees = x;
		employees = new Employee[x];
		for (int i=0; i<x; i++){
			employees [i] = new Employee (i);
		}
	}
	
	public Premise getPremise(){
		return premises;
	}
	public void setPremise(Premise p){
		premises = p;
	}
	
	public String getSerialNo(){
		return serialNo;
	}
	public void setSerialNo(String s){
		serialNo = s;
	}
	
	public String getName(){
		return companyName;
	}
	public void setCompanyName(String s){
		companyName =s;
	}
	
	public String getBusinessCode(){
		return businessCode;
	}
	public void setBusinessCode(String s) {
		businessCode= s;
	}
	
	public String getSector(){
		return sector;
	}
	public void setSector(String s){
		sector = s;
	}
	
	public double getTurnOver(){
		return turnOver;
	}
	public void setTurnOver(double x){
		turnOver = x;
	}
	public Employee[] getEmployeesHistory(){
		return employees;
	}
	public void allocateEmployees (BehaviourSME b, int x){
		int localIdleEmployees =0;
		for(int i=0; i<numberEmployees; i++){
			Employee e = employees[i];
			if(!e.isBusy()){
				localIdleEmployees ++;
				if(localIdleEmployees >0 && localIdleEmployees<=x){
					e.setBusy(true);
					BehaviourHistory history = new BehaviourHistory(b);
					e.getBehaviourHistory().add(history);
					history.setStart(b.getExecutedTime());
	//				e.getBehaviourHistory().add(b.getBehaviourName());
					//System.out.println("--------Employee " +e.getEmployeeCode()+" is allocated to do "+ b.getBehaviourName());
				}				
			}
		}
		if(localIdleEmployees<x){
			System.out.println(this.getName()+" does not have " +x +" staff to allocate to the work" + b.getBehaviourName()+" !!!");
		}
	}
	/**
	 * This method set the employees' status to not-busy and record the end time of the behaviour in the behaviour history.
	 * @param b
	 */
	public void releaseEmployees (BehaviourSME b){
		for(int i=0; i<numberEmployees; i++){
			Employee e = employees[i];			
			if(e.isBusy()){
				LinkedList<BehaviourHistory> behaviours = e.getBehaviourHistory();
				if(behaviours.getLast().getName().equals(b.getBehaviourName())){
					e.setBusy(false);
					behaviours.getLast().setEnd(b.getEndTime());
				}
			}
		}
	}
	
	public boolean isMultiLocation(){
		return multiLocation;
	}
	public void setMultiLocation (boolean b){
		multiLocation = b;
	}
	
	public boolean isCoveredByInsurance(){
		return coveredByInsurance;
	}
	public void setInsurance (boolean b){
		coveredByInsurance = b;
	}
	
	public boolean getHasEngineers(){
		return hasEngineers;
	}
	public void setHasEngineers(boolean b){
		hasEngineers = b;
	}
	
	public LinkedList<SME> getNeighbours(){
		return neighbours;
	}
	public void setNeighbours(LinkedList<SME> list){
		neighbours = list;
	}
	
	public void addNewNeighbour(SME sme){
		neighbours.add(sme);
	//	sme.addNewNeighbour(this);
	}
	
	public ContactsOfSme getContacts(){
		return contacts;
	}
	
	public Clock getClock(){
		return clock;
	}
	public boolean getPowerOn(){
		return powerOn;
	}
	public void setPowerOn(boolean b){
			powerOn = b;
    }
	public boolean getCashAvailable(){
		return cashAvailableForRecovery;
	}
	public void setCashAvailable(boolean b){
		cashAvailableForRecovery = b;
	}
	
	public abstract void step();
	public abstract void updateReceiver();
	public void setAbsentees(int x){
		numberVacancy=x;
	}
	public int getNumberVacancy(){
		return numberVacancy;
	}
	
	public MsgSender getSender(){
		return sender;		
	}
	
	public MsgReceiver getReceiver(){
		return receiver;
	}
	public String toString(){
		return getSerialNo()+" Company:"+getName()+" Business code: "+ getBusinessCode()+
				"; size: "+numberEmployees+"; turnover: "+ getTurnOver() +"; premises: "+ premises.toString()+
				"; Multilocation: "+isMultiLocation() + "; Function:" +getSector() +"; Trust EA: "+ getTrustEA() + "; Capability: " + getCapability()
				+ "; Participate mutual aid: " +participateMutualAid;		
	}
}
